package com.example.springbootsecurity.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 密码生成策略
     * 不使用加密算法的话使用NoOpPasswordEncoder.getInstance();但已弃用，新版本需要对密码进行加密
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        // new BCryptPasswordEncoder();
        return NoOpPasswordEncoder.getInstance();
    }

    //注入我们自己的AuthenticationProvider
    @Autowired
    private AuthenticationProvider provider;

    @Autowired
    private MyAuthenticationHandler myAuthenticationHandler;

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Autowired
    private MyPersistentTokenRepository redisTokenRepository;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(provider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 关闭csrf防护
                .csrf().disable()
                .headers().frameOptions().disable()
                .and();
        http
                //登录处理
                .formLogin() //表单方式，或httpBasic
                .loginPage("/loginPage")
                .loginProcessingUrl("/form")
                .successHandler(myAuthenticationHandler)
                .failureHandler(myAuthenticationHandler)
                .permitAll()
                .and();
        http.rememberMe()
                .rememberMeParameter("remember-me")
                .userDetailsService(userDetailsService)
                .tokenRepository(redisTokenRepository)
                .tokenValiditySeconds(60)
                .and();
        http
                .authorizeRequests() // 授权配置
                //无需权限访问
                //.antMatchers("/whoim").permitAll()
                .antMatchers( "/css/**", "/error404","/whoim").permitAll()
                .antMatchers("/testShiro").hasRole("ADMIN")
                //这就表示/whoim的这个资源需要有ROLE_ADMIN的这个角色才能访问。不然就会提示拒绝访问
                .antMatchers("/user/**").hasRole("USER")
                //必须经过认证以后才能访问
                //.anyRequest().access("@rbacService.hasPermission(request,authentication)")
                //需要被注释, Can't configure anyRequest after itself
                // 因为所有配置项取得是交集,如果这一项在的话就表示只要认证就可以访问了
                .anyRequest().authenticated()
                .and();
    }

}
